package com.framework.shs.commom.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;

import javassist.bytecode.analysis.Analyzer;

import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.params.SolrParams;
import org.wltea.analyzer.lucene.IKAnalyzer;

import com.framework.shs.commom.paginate.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * 
 * 
 * @time 2016-7-1
 * @author : sharker
 * 
 */
@SuppressWarnings("all")
public class SolrUtils {
	private static String URL = "";
	private static HttpSolrServer server = SpringContextHolder.getBean(HttpSolrServer.class);
	static IKAnalyzer analyzer ;
	static {
		analyzer = new IKAnalyzer();
	}

	private SolrUtils() {
	}


	public static HttpSolrServer getServer() {
		return server;
	}

	/**
	 * @Description: 添加单个对象到索引
	 * @author kang
	 * @创建时间 2015下午2:59:50
	 * @param @param object
	 * @param @throws IOException
	 * @param @throws SolrServerException
	 * @return void
	 * @throws
	 */
	public void addBean(Object object) throws IOException, SolrServerException {
		server.addBean(object);
		server.commit(false, false);
	}

	/**
	 * @Description: 添加集合到索引
	 * @author kang
	 * @创建时间 2015下午3:02:23
	 * @param @param lists
	 * @param @throws SolrServerException
	 * @param @throws IOException
	 * @return void
	 * @throws
	 */
	public <E> void addBeans(List<E> lists) throws SolrServerException,
			IOException {
		server.addBeans(lists);
		server.commit(false, false);
	}

	/**
	 * @Description: 根据id删除记录
	 * @author kang
	 * @创建时间 2015下午5:10:54
	 * @param @param idName
	 * @param @param id
	 * @param @throws SolrServerException
	 * @param @throws IOException
	 * @return void
	 * @throws
	 */
	public void deleteById(String idName, Object id)
			throws SolrServerException, IOException {
		server.deleteByQuery(idName + ":" + id.toString());
		server.commit(false, false);
	}

	/**
	 * @Description: 根据ids批量删除
	 * @author kang
	 * @创建时间 2015下午5:26:39
	 * @param @param idName
	 * @param @param ids
	 * @param @throws SolrServerException
	 * @param @throws IOException
	 * @return void
	 * @throws
	 */
	public <E> void deleteByIds(String idName, List<E> ids)
			throws SolrServerException, IOException {
		if (ids.size() > 0) {
			StringBuffer query = new StringBuffer(idName + ":" + ids.get(0));
			for (int i = 1; i < ids.size(); i++) {
				if (null != ids.get(i)) {
					query.append(" OR " + idName + ":" + ids.get(i).toString());
				}
			}
			server.deleteByQuery(query.toString());
			server.commit(false, false);
		}
	}

	/**
	 * 
	 * @Description: 根据查询从索引删除
	 * @author kang
	 * @创建时间 2015下午5:32:35
	 * @param @param query
	 * @param @throws SolrServerException
	 * @param @throws IOException
	 * @return void
	 * @throws
	 */
	public void deleteByQuery(String query) throws SolrServerException,
			IOException {
		server.deleteByQuery(query);
		server.commit(false, false);
	}

	/**
	 * 
	 * @Description: 删除所有
	 * @author kang
	 * @创建时间 2015下午5:36:21
	 * @param @throws SolrServerException
	 * @param @throws IOException
	 * @return void
	 * @throws
	 */
	public void deleteAll() throws SolrServerException, IOException {
		server.deleteByQuery("*:*");
		server.commit(false, false);
	}

	/**
	 * @Description: 关键字分页查询
	 * @author kang
	 * @创建时间 2015下午4:54:24
	 * @param @param keyword
	 * @param @param pageNum
	 * @param @param pageSize
	 * @param @param clzz
	 * @param @return
	 * @return Page<T>
	 * @throws
	 */
	public <T> Page<T> getByPage(String keywords, int pageNum, int pageSize,
			Class<T> clzz, String lang, Boolean distinguish) {
		SolrQuery query = new SolrQuery();
		query.setQuery(keywords)// 查询内容
				.setStart((pageNum - 1) * pageSize)// 分页
				.setRows(pageSize);//
		if (distinguish) {
			query.addFilterQuery("lang:" + lang);// 中英文区别
		}
		QueryResponse response = null;
		try {
			response = server.query(query);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		// 查询结果集
		SolrDocumentList results = response.getResults();
		// 获取对象
		List<T> beans = server.getBinder().getBeans(clzz, results);
		// 总记录数
		int total = new Long(response.getResults().getNumFound()).intValue();
		return new Page<T>(pageNum, pageSize, total, beans);
	}

	/**
	 * @Description: 判断是否有索引数据
	 * @author kang
	 * @创建时间 2015下午4:54:24
	 * @param @param keyword
	 * @param @param pageNum
	 * @param @param pageSize
	 * @param @param clzz
	 * @param @return
	 * @return Page<T>
	 * @throws
	 */
	public boolean hasIndex() {
		SolrQuery query = new SolrQuery();
		query.setQuery("*:*")// 查询内容
				.setStart(0)// 分页
				.setRows(1);
		QueryResponse response = null;
		try {
			response = server.query(query);
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		// 总记录数
		int total = new Long(response.getResults().getNumFound()).intValue();
		return total == 0 ? false : true;
	}

	/**
	 * 
	 * @Description:带高亮的关键字查询
	 * @author kang
	 * @创建时间 2015下午9:03:02
	 * @param @param keywords
	 * @param @param pageNum
	 * @param @param pageSize
	 * @param @param hlFields
	 * @param @param preTag
	 * @param @param postTag
	 * @param @param clzz
	 * @param @param idName
	 * @param @return
	 * @return Page<T>
	 * @throws
	 */
	public <T> Page<T> getHighterByPage(String keywords, int pageNum,
			int pageSize, List<String> hlFields, String preTag, String postTag,
			Class<T> clzz, String idName, String lang, Boolean distinguish) {
		SolrQuery query = new SolrQuery();
		query.setQuery(keywords)// 查询内容
				.setHighlight(true)// 设置高亮显示
				.setHighlightSimplePre(preTag)// 渲染头标签
				.setHighlightSimplePost(postTag)// 尾标签
				.setStart((pageNum - 1) * pageSize)// 分页
				.setRows(pageSize);//
		if (distinguish) {
			query.addFilterQuery("lang:" + lang);// 中英文区别
		}
		// 设置高亮区域
		for (String hl : hlFields) {
			query.addHighlightField(hl);
		}
		QueryResponse response = null;

		try {
			response = server.query(query);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}

		SolrDocumentList results = response.getResults();
		// 总记录数
		int total = new Long(results.getNumFound()).intValue();
		// 查询结果集
		List<T> list = new ArrayList<T>();

		try {
			Object object = null;
			Method method = null;
			Class<?> fieldType = null;
			Map<String, Map<String, List<String>>> map = response
					.getHighlighting();
			for (SolrDocument solrDocument : results) {
				object = clzz.newInstance();
				// 得到所有属性名
				Collection<String> fieldNames = solrDocument.getFieldNames();
				for (String fieldName : fieldNames) {
					Field[] fields = clzz.getDeclaredFields();
					for (Field f : fields) {
						// 如果实体属性名和查询返回集中的字段名一致，填充对应的set方法
						if (f.getName().equals(fieldName)) {
							f = clzz.getDeclaredField(fieldName);
							fieldType = f.getType();
							// 构造set方法名 setId
							String dynamicSetMethod = dynamicMethodName(
									f.getName(), "set");
							// 获取方法
							method = clzz
									.getMethod(dynamicSetMethod, fieldType);
							// 获取fieldType类型
							// fieldType = getFileType(fieldType);
							// 获取到的属性
							method.invoke(object, fieldType.cast(solrDocument
									.getFieldValue(fieldName)));
							for (String hl : hlFields) {
								if (hl.equals(fieldName)) {
									String idv = solrDocument.getFieldValue(
											idName).toString();
									List<String> hfList = map.get(idv).get(
											fieldName);
									if (null != hfList && hfList.size() > 0) {
										// 高亮添加
										method.invoke(object,
												fieldType.cast(hfList.get(0)));
									} else {
										method.invoke(
												object,
												fieldType.cast(solrDocument
														.getFieldValue(fieldName)));
									}
								}
							}
						}
					}
				}
				list.add(clzz.cast(object));
			}
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		return new Page<T>(pageNum, pageSize, total, list);
	}

	/**
	 * @Description: 动态生成方法名
	 * @author kang
	 * @创建时间 2015下午9:16:59
	 * @param @param name
	 * @param @param string
	 * @param @return
	 * @return String
	 * @throws
	 */
	private String dynamicMethodName(String name, String string) {
		if (Character.isUpperCase(name.charAt(0)))
			return string + name;
		else
			return (new StringBuilder())
					.append(string + Character.toUpperCase(name.charAt(0)))
					.append(name.substring(1)).toString();
	}

	/**
	 * @Description:因为反射的属性可能是一个集合,所以在利用反射转换之前,需要进行更精确地判断,这实例中实体对象中的属性为简单类型,所以这个方法可以处理
	 * @author kang
	 * @创建时间 2015下午6:59:17
	 * @param @param fieldType
	 * @param @return
	 * @return Class<?>
	 * @throws
	 */
	public Class<?> getFileType(Class<?> fieldType) {
		// 如果是 int, float等基本类型，则需要转型
		if (fieldType.equals(Integer.TYPE)) {
			return Integer.class;
		} else if (fieldType.equals(Float.TYPE)) {
			return Float.class;
		} else if (fieldType.equals(Double.TYPE)) {
			return Double.class;
		} else if (fieldType.equals(Boolean.TYPE)) {
			return Boolean.class;
		} else if (fieldType.equals(Short.TYPE)) {
			return Short.class;
		} else if (fieldType.equals(Long.TYPE)) {
			return Long.class;
		} else if (fieldType.equals(String.class)) {
			return String.class;
		} else if (fieldType.equals(Collection.class)) {
			return Collection.class;
		}
		return null;
	}

	/**
	 * 查询
	 *
	 * @time : 2016-7-1
	 * @author : sharker
	 *
	 */
	public static QueryResponse querySolr(String q){
		SolrParams params =new SolrQuery(q);
		QueryResponse response = null;
		try {
			 response = SolrUtils.getServer().query(params);
		} catch (SolrServerException | IOException e) {
			new SolrServerException("solr查询异常");
		}
		return response;
	}
	
	/**
	 * 根据solrDcument的Id获取其字段内容
	 * 
	 * @param id
	 * @throws SolrServerException
	 */
	public static String getDocumentById(String id) {
		SolrQuery query = new SolrQuery();
		query.set("q", "id:" + id);
		String content = null;
		try {
			SolrDocumentList results = server.query(query).getResults();
			for (SolrDocument doc : results) {
				content = (String) doc.getFieldValue("user_name");
				/*
				 * Map<String, Object> map = doc.getFieldValueMap(); Set<String>
				 * keySet = map.keySet(); for (String key : keySet) {
				 * System.out.println(map.get(key)); }
				 */
			}
		} catch (SolrServerException | IOException e) {
			e.printStackTrace();
		}
		return content;
	}
	
	
	
	/**
	 * 全文检索,关键字搜索文件相关,高亮显示
	 * @author baoyt
	 * @param search 搜索关键字/词
	 * @param filed 搜索/高亮 字段
	 * @param index 从第几条开始,默认为0
	 * @param size 查询多少条数据 默认 20
	 * @param fragsize 摘要信息的长度。默认值是100，这个长度是出现关键字的位置向前移6个字符，再往后100个字符，取这一段文本。
	 * @return 
	 */
	public static Map<String, Map<String, List<String>>> searchHighlighting(String search,String filed,Integer index,Integer size,Integer fragsize) {
		// 智能分词-----------------------
		CharTermAttribute ta = null;
		String params = "";
		Map<String, Map<String, List<String>>> map =null;
		try {
			IKAnalyzer analyzer=new IKAnalyzer();
			analyzer.setUseSmart(true);// 使用智能分词
			TokenStream stream = analyzer.tokenStream("", new StringReader(search));// 分词字段
			ta = stream.addAttribute(CharTermAttribute.class);
			stream.reset();
			// 分拼接查询条件
			for (; stream.incrementToken();) {
				params += filed+":*" + ta + "* OR ";
			}
			stream.end();
		} catch (IOException e1) {
			e1.printStackTrace();
		}finally{
			analyzer.close();
		}
		// -----------------------------end
		SolrQuery query = new SolrQuery();
		String para = "";
		if (params != null) {
			if (params.lastIndexOf("OR") != -1)
				params = params.substring(0, params.lastIndexOf("OR"));
			para = params;
		}
		/** 参考 :http://blog.csdn.net/okman1214/article/details/10461595 */
		// query.addSort("file_update_date", ORDER.asc);
		query.set("q", para); // 说明：set比setQuery的范围大一些，如果是 ik 分词建议用set
		/**
		 * HighlightSnippets参数是返回高亮摘要的段数，因为我们的文本一般都比较长，含有搜索关键字的地方有多处，
		 * 如果hl.snippets的值大于1的话，会返回多个摘要信息，即文本中含有关键字的几段话，默认值为1，
		 * 返回含关键字最多的一段描述。solr会对多个段进行排序。
		 */
		query.setHighlightSnippets(1);
		/**
		 * 设置"起始位置"：表示从结果集的第几条数据开始显示。默认下标是0开始
		 */
		 query.setStart(null==index?0:index); //下标
		 query.setRows(null==size?20:size); // 设置每页显示的行数
		/**
		 * fragsize参数是摘要信息的长度。默认值是100，这个长度是出现关键字的位置向前移6个字符，再往后100个字符，取这一段文本。
		 */
//		query.setHighlightFragsize(100);
		query.setHighlight(true); // 开启高亮功能
		query.addHighlightField(filed); // 高亮字段
		query.setHighlightSimplePre("<font color=\"red\">"); // 渲染标签
		query.setHighlightSimplePost("</font>"); // 渲染标签
		QueryResponse response;
		try {
			response = server.query(query);
			// SolrDocumentList dlist = response.getResults();//查询结果
			// 第一 个Map的键是文档的ID，第二个Map的键是高亮显示的字段名
			 map = response.getHighlighting();
			/*Set<String> keySet = map.keySet();
			for (String key : keySet) {
				// 检索出来的文档ID
				System.out.println("ID:     " + key);
				Map<String, List<String>> map2 = map.get(key);
				for (String k : map2.keySet()) {
					List<String> list = map2.get(k);
					// 检索出来的字段值
					System.out.println("内容是:    " + list.get(0));
				}
			}*/
		} catch (SolrServerException  | IOException e) {
			new SolrServerException("solr异常");
		}
		return map;
	}
}
